"""
Open Interpreter 适配器
将 Open Interpreter 的核心计算机控制功能集成到现有的语音对话控制系统中
"""

import os
import time
import json
from typing import Any, Dict, List, Optional, Tuple, Union

try:
    import pyautogui
    import pywinauto
    from pywinauto import Application
    import mss
    import cv2
    import numpy as np
    from PIL import ImageGrab, Image
    import screeninfo
    import pygetwindow as gw
    HAS_PYAUTOGUI = True
except ImportError as e:
    print(f"Warning: Some dependencies for Open Interpreter adapter are missing: {e}")
    HAS_PYAUTOGUI = False
    # 创建占位符类
    class Image:
        class Image:
            pass
    ImageGrab = None
    gw = None

from .logger import log_event
from .config import Config


class OpenInterpreterAdapter:
    """
    Open Interpreter 风格的计算机控制适配器
    提供更丰富的计算机控制功能，同时保持与现有系统的兼容性
    """
    
    def __init__(self):
        self.setup_pyautogui()
        self._last_screenshot = None
        self._screenshot_cache_time = 0
        self._cache_duration = 1.0  # 截图缓存1秒
        
    def setup_pyautogui(self):
        """配置 pyautogui 的安全设置"""
        if pyautogui:
            pyautogui.FAILSAFE = True  # 鼠标移到左上角停止
            pyautogui.PAUSE = 0.1  # 每个操作间隔0.1秒
            
    # ==================== 屏幕操作 ====================
    
    def screenshot(self, region: Optional[Tuple[int, int, int, int]] = None) -> Optional['Image.Image']:
        """
        截取屏幕截图
        Args:
            region: (x, y, width, height) 截图区域，None表示全屏
        Returns:
            PIL Image对象
        """
        try:
            if ImageGrab is None:
                raise RuntimeError("ImageGrab not available")
            current_time = time.time()
            # 使用缓存避免频繁截图
            if (self._last_screenshot is not None and 
                current_time - self._screenshot_cache_time < self._cache_duration and
                region is None):
                return self._last_screenshot
                
            if region:
                screenshot = ImageGrab.grab(bbox=region)
            else:
                screenshot = ImageGrab.grab()
                
            if region is None:
                self._last_screenshot = screenshot
                self._screenshot_cache_time = current_time
                
            return screenshot
        except Exception as e:
            log_event("SCREENSHOT_ERROR", f"截图失败: {e}")
            return None
    
    def find_text_on_screen(self, text: str, region: Optional[Tuple[int, int, int, int]] = None) -> Optional[Tuple[int, int, int, int]]:
        """
        在屏幕上查找文本位置
        Args:
            text: 要查找的文本
            region: 搜索区域 (x, y, width, height)
        Returns:
            文本位置 (x, y, width, height) 或 None
        """
        try:
            screenshot = self.screenshot(region)
            if not screenshot:
                return None
                
            # 转换为OpenCV格式
            cv_image = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
            
            import pytesseract
            # 使用OCR识别文本
            ocr_data = pytesseract.image_to_data(cv_image, output_type=pytesseract.Output.DICT)
            
            # 查找匹配的文本
            for i, detected_text in enumerate(ocr_data['text']):
                if text.lower() in detected_text.lower() and int(ocr_data['conf'][i]) > 30:
                    x = ocr_data['left'][i]
                    y = ocr_data['top'][i]
                    w = ocr_data['width'][i]
                    h = ocr_data['height'][i]
                    
                    # 如果指定了搜索区域，需要调整坐标
                    if region:
                        x += region[0]
                        y += region[1]
                    
                    return (x, y, w, h)
            
            return None
        except Exception as e:
            log_event("FIND_TEXT_ERROR", f"查找文本失败: {e}")
            return None
    
    def find_image_on_screen(self, template_path: str, confidence: float = 0.8) -> Optional[Tuple[int, int]]:
        """
        在屏幕上查找图像
        
        Args:
            template_path: 模板图像路径
            confidence: 匹配置信度 (0-1)
            
        Returns:
            匹配位置的中心坐标，未找到返回None
        """
        if not HAS_PYAUTOGUI:
            log_event("FIND_IMAGE_ERROR", "pyautogui not available")
            return None
            
        try:
            # 截取屏幕
            screenshot = self.screenshot()
            if not screenshot:
                return None
            
            # 加载模板图像
            template = cv2.imread(template_path)
            if template is None:
                log_event("FIND_IMAGE_ERROR", f"Cannot load template image: {template_path}")
                return None
            
            # 转换为OpenCV格式
            screen_cv = cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
            
            # 模板匹配
            result = cv2.matchTemplate(screen_cv, template, cv2.TM_CCOEFF_NORMED)
            min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
            
            if max_val >= confidence:
                # 计算中心点
                h, w = template.shape[:2]
                center_x = max_loc[0] + w // 2
                center_y = max_loc[1] + h // 2
                
                log_event("FIND_IMAGE_SUCCESS", f"Found image at ({center_x}, {center_y}) with confidence {max_val}")
                return (center_x, center_y)
            else:
                log_event("FIND_IMAGE_FAILED", f"Image not found, best match confidence: {max_val}")
                return None
                
        except Exception as e:
            log_event("FIND_IMAGE_ERROR", f"Error finding image: {e}")
            return None
    
    # ==================== 鼠标操作 ====================
    
    def click(self, x: int, y: int, button: str = 'left', clicks: int = 1) -> bool:
        """点击指定坐标"""
        try:
            if not pyautogui:
                return False
            pyautogui.click(x, y, clicks=clicks, button=button)
            return True
        except Exception as e:
            log_event("CLICK_ERROR", f"点击失败: {e}")
            return False
    
    def click_text(self, text: str, region: Optional[Tuple[int, int, int, int]] = None) -> bool:
        """点击屏幕上的文本"""
        try:
            text_location = self.find_text_on_screen(text, region)
            if text_location:
                x, y, w, h = text_location
                center_x = x + w // 2
                center_y = y + h // 2
                return self.click(center_x, center_y)
            return False
        except Exception as e:
            log_event("CLICK_TEXT_ERROR", f"点击文本失败: {e}")
            return False
    
    def click_image(self, template_path: str, confidence: float = 0.8) -> bool:
        """点击屏幕上的图像"""
        try:
            image_location = self.find_image_on_screen(template_path, confidence)
            if image_location:
                x, y = image_location
                return self.click(x, y)
            return False
        except Exception as e:
            log_event("CLICK_IMAGE_ERROR", f"点击图像失败: {e}")
            return False
    
    def drag(self, start_x: int, start_y: int, end_x: int, end_y: int, duration: float = 1.0) -> bool:
        """拖拽操作"""
        try:
            if not pyautogui:
                return False
            pyautogui.drag(end_x - start_x, end_y - start_y, duration=duration)
            return True
        except Exception as e:
            log_event("DRAG_ERROR", f"拖拽失败: {e}")
            return False
    
    def scroll(self, clicks: int, x: Optional[int] = None, y: Optional[int] = None) -> bool:
        """滚轮操作"""
        try:
            if not pyautogui:
                return False
            if x is not None and y is not None:
                pyautogui.scroll(clicks, x=x, y=y)
            else:
                pyautogui.scroll(clicks)
            return True
        except Exception as e:
            log_event("SCROLL_ERROR", f"滚轮操作失败: {e}")
            return False
    
    # ==================== 键盘操作 ====================
    
    def type_text(self, text: str, interval: float = 0.01) -> bool:
        """输入文本"""
        try:
            if not pyautogui:
                return False
            pyautogui.typewrite(text, interval=interval)
            return True
        except Exception as e:
            log_event("TYPE_ERROR", f"输入文本失败: {e}")
            return False
    
    def press_key(self, key: str) -> bool:
        """按键"""
        try:
            if not pyautogui:
                return False
            pyautogui.press(key)
            return True
        except Exception as e:
            log_event("PRESS_KEY_ERROR", f"按键失败: {e}")
            return False
    
    def hotkey(self, *keys) -> bool:
        """组合键"""
        try:
            if not pyautogui:
                return False
            pyautogui.hotkey(*keys)
            return True
        except Exception as e:
            log_event("HOTKEY_ERROR", f"组合键失败: {e}")
            return False
    
    # ==================== 窗口操作 ====================
    
    def get_active_window(self) -> Optional[Dict[str, Any]]:
        """获取当前活动窗口信息"""
        try:
            if not gw:
                return None
            active_window = gw.getActiveWindow()
            if active_window:
                return {
                    'title': active_window.title,
                    'left': active_window.left,
                    'top': active_window.top,
                    'width': active_window.width,
                    'height': active_window.height
                }
            return None
        except Exception as e:
            log_event("GET_WINDOW_ERROR", f"获取窗口信息失败: {e}")
            return None
    
    def find_window(self, title_contains: str) -> Optional[Dict[str, Any]]:
        """查找包含指定标题的窗口"""
        try:
            if not gw:
                return None
            windows = gw.getWindowsWithTitle(title_contains)
            if windows:
                window = windows[0]
                return {
                    'title': window.title,
                    'left': window.left,
                    'top': window.top,
                    'width': window.width,
                    'height': window.height,
                    'window_obj': window
                }
            return None
        except Exception as e:
            log_event("FIND_WINDOW_ERROR", f"查找窗口失败: {e}")
            return None
    
    def activate_window(self, title_contains: str) -> bool:
        """激活窗口"""
        try:
            window_info = self.find_window(title_contains)
            if window_info and 'window_obj' in window_info:
                window_info['window_obj'].activate()
                return True
            return False
        except Exception as e:
            log_event("ACTIVATE_WINDOW_ERROR", f"激活窗口失败: {e}")
            return False
    
    # ==================== 高级操作 ====================
    
    def wait_for_text(self, text: str, timeout: float = 10.0, region: Optional[Tuple[int, int, int, int]] = None) -> bool:
        """等待文本出现"""
        start_time = time.time()
        while time.time() - start_time < timeout:
            if self.find_text_on_screen(text, region):
                return True
            time.sleep(0.5)
        return False
    
    def wait_for_image(self, template_path: str, timeout: float = 10.0, confidence: float = 0.8) -> bool:
        """等待图像出现"""
        start_time = time.time()
        while time.time() - start_time < timeout:
            if self.find_image_on_screen(template_path, confidence):
                return True
            time.sleep(0.5)
        return False
    
    def execute_computer_action(self, action: Dict[str, Any]) -> Tuple[bool, str]:
        """
        执行计算机操作动作
        这是与现有 ActionExecutor 集成的主要接口
        """
        try:
            action_type = action.get('type', '')
            
            if action_type == 'click_text':
                text = action.get('text', '')
                region = action.get('region')
                success = self.click_text(text, region)
                return success, f"点击文本 '{text}' {'成功' if success else '失败'}"
            
            elif action_type == 'click_image':
                image_path = action.get('image_path', '')
                confidence = action.get('confidence', 0.8)
                success = self.click_image(image_path, confidence)
                return success, f"点击图像 {'成功' if success else '失败'}"
            
            elif action_type == 'type_text':
                text = action.get('text', '')
                success = self.type_text(text)
                return success, f"输入文本 '{text}' {'成功' if success else '失败'}"
            
            elif action_type == 'press_key':
                key = action.get('key', '')
                success = self.press_key(key)
                return success, f"按键 '{key}' {'成功' if success else '失败'}"
            
            elif action_type == 'hotkey':
                keys = action.get('keys', [])
                success = self.hotkey(*keys)
                return success, f"组合键 {keys} {'成功' if success else '失败'}"
            
            elif action_type == 'scroll':
                clicks = action.get('clicks', 0)
                x = action.get('x')
                y = action.get('y')
                success = self.scroll(clicks, x, y)
                return success, f"滚轮操作 {'成功' if success else '失败'}"
            
            elif action_type == 'activate_window':
                title = action.get('title', '')
                success = self.activate_window(title)
                return success, f"激活窗口 '{title}' {'成功' if success else '失败'}"
            
            elif action_type == 'wait_for_text':
                text = action.get('text', '')
                timeout = action.get('timeout', 10.0)
                region = action.get('region')
                success = self.wait_for_text(text, timeout, region)
                return success, f"等待文本 '{text}' {'成功' if success else '超时'}"
            
            else:
                return False, f"不支持的操作类型: {action_type}"
                
        except Exception as e:
            error_msg = f"执行操作失败: {e}"
            log_event("EXECUTE_ACTION_ERROR", error_msg)
            return False, error_msg